#include "KgBackTrace.h"

#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <signal.h>
#include <execinfo.h>

// //ISO C99 signals.
// #define	SIGINT		2	/* Interactive attention signal.  */
// #define	SIGILL		4	/* Illegal instruction.  */
// #define	SIGABRT		6	/* Abnormal termination.  */
// #define	SIGFPE		8	/* Erroneous arithmetic operation.  */
// #define	SIGSEGV		11	/* Invalid access to storage.  */
// #define	SIGTERM		15	/* Termination request.  */

// //Historical signals specified by POSIX.
// #define	SIGHUP		1	/* Hangup.  */
// #define	SIGQUIT		3	/* Quit.  */
// #define	SIGTRAP		5	/* Trace/breakpoint trap.  */
// #define	SIGKILL		9	/* Killed.  */
// #define SIGBUS		10	/* Bus error.  */
// #define	SIGSYS		12	/* Bad system call.  */
// #define	SIGPIPE		13	/* Broken pipe.  */
// #define	SIGALRM		14	/* Alarm clock.  */

// //New(er) POSIX signals (1003.1-2008, 1003.1-2013).
// #define	SIGURG		16	/* Urgent data is available at a socket.  */
// #define	SIGSTOP		17	/* Stop, unblockable.  */
// #define	SIGTSTP		18	/* Keyboard stop.  */
// #define	SIGCONT		19	/* Continue.  */
// #define	SIGCHLD		20	/* Child terminated or stopped.  */
// #define	SIGTTIN		21	/* Background read from control terminal.  */
// #define	SIGTTOU		22	/* Background write to control terminal.  */
// #define	SIGPOLL		23	/* Pollable event occurred (System V).  */
// #define	SIGXCPU		24	/* CPU time limit exceeded.  */
// #define	SIGXFSZ		25	/* File size limit exceeded.  */
// #define	SIGVTALRM	26	/* Virtual timer expired.  */
// #define	SIGPROF		27	/* Profiling timer expired.  */
// #define	SIGUSR1		30	/* User-defined signal 1.  */
// #define	SIGUSR2		31	/* User-defined signal 2.  */

// // Nonstandard signals found in all modern POSIX systems
// //   (including both BSD and Linux).
// #define	SIGWINCH	28	/* Window size change (4.3 BSD, Sun).  */

// // Archaic names for compatibility.
// #define	SIGIO		SIGPOLL	/* I/O now possible (4.2 BSD).  */
// #define	SIGIOT		SIGABRT	/* IOT instruction, abort() on a PDP-11.  */
// #define	SIGCLD		SIGCHLD	/* Old System V name

#define ADDR_MAX_NUM 100

//初始化异常处理
void InitBackTrace()
{
    signal(SIGINT, BackTraceHandler);
    signal(SIGILL, BackTraceHandler);
    signal(SIGABRT, BackTraceHandler);
    signal(SIGFPE, BackTraceHandler);
    signal(SIGSEGV, BackTraceHandler);

    signal(SIGTERM, BackTraceHandler);
    // signal(SIGBREAK, BackTraceHandler);
    // signal(SIGHUP, BackTraceHandler);
    // signal(SIGQUIT, BackTraceHandler);
    // signal(SIGTRAP, BackTraceHandler);

    // signal(SIGKILL, BackTraceHandler);
    // signal(SIGBUS, BackTraceHandler);
    // signal(SIGSYS, BackTraceHandler);
    // signal(SIGPIPE, BackTraceHandler);
    // signal(SIGALRM, BackTraceHandler);

    // signal(SIGURG, BackTraceHandler);
    // signal(SIGSTOP, BackTraceHandler);
    // signal(SIGTSTP, BackTraceHandler);
    // signal(SIGCONT, BackTraceHandler);
    // signal(SIGCHLD, BackTraceHandler);

    // signal(SIGTTIN, BackTraceHandler);
    // signal(SIGTTOU, BackTraceHandler);
    // signal(SIGPOLL, BackTraceHandler);
     signal(SIGXCPU, BackTraceHandler);
    // signal(SIGXFSZ, BackTraceHandler);

    // signal(SIGVTALRM, BackTraceHandler);
    // signal(SIGPROF, BackTraceHandler);
    // signal(SIGUSR1, BackTraceHandler);
    // signal(SIGUSR2, BackTraceHandler);
    // signal(SIGIO, BackTraceHandler);

    // signal(SIGIOT, BackTraceHandler);
    // signal(SIGCLD, BackTraceHandler);
}

//异常的文字描述
QString SignalText(int iSignalNo)
{
    QString strText = "";

    switch(iSignalNo)
    {
    case SIGINT:
        strText = "硬中断 Interactive attention signal";
        break;
    case SIGILL:
        strText = "非法指令 illegal instruction-invalid function image";
        break;
    case SIGFPE:
        strText = "浮点异常 floating point exception";
        break;
    case SIGSEGV:
        strText = "段错误 segment violation";
        break;
    case SIGTERM:
        strText = "杀进程 Software termination signal from kill";
        break;
//    case SIGBREAK:
//        strText = "中断 Ctrl-Break sequence";
//        break;
    case SIGABRT:
        strText = "异常终止 abnormal termination triggered by abort call";
        break;
    case SIGHUP:
        strText = "Hangup.";
        break;
    case SIGQUIT:
        strText = "Quit.";
        break;
    case SIGTRAP:
        strText = "Trace/breakpoint trap.";
        break;
    case SIGKILL:
        strText = "Killed.";
        break;
    case SIGBUS:
        strText = "Bus error.";
        break;
    case SIGSYS:
        strText = "Bad system call.";
        break;
    case SIGPIPE:
        strText = "Broken pipe.";
        break;
    case SIGALRM:
        strText = "Alarm clock.";
        break;
    case SIGURG:
        strText = "Urgent data is available at a socket.";
        break;
    case SIGSTOP:
        strText = "Stop, unblockable.";
        break;
    case SIGTSTP:
        strText = "Keyboard stop.";
        break;
    case SIGCONT:
        strText = "Continue.";
        break;
    case SIGCHLD:
        strText = "Child terminated or stopped.";
        break;
    case SIGTTIN:
        strText = "Background read from control terminal.";
        break;
    case SIGTTOU:
        strText = "Background write to control terminal.";
        break;
    case SIGPOLL:
        strText = "Pollable event occurred (System V).";
        break;
    case SIGXCPU:
        strText = "CPU time limit exceeded.";
        break;
    case SIGXFSZ:
        strText = "File size limit exceeded.";
        break;
    case SIGVTALRM:
        strText = "Virtual timer expired.";
        break;
    case SIGPROF:
        strText = "Profiling timer expired.";
        break;
    case SIGUSR1:
        strText = "User-defined signal 1.";
        break;
    case SIGUSR2:
        strText = "User-defined signal 2.";
        break;
    case SIGWINCH:
        strText = "Window size change (4.3 BSD, Sun).";
        break;
//    case SIGIO:
//        strText = "I/O now possible (4.2 BSD)";
//        break;
//    case SIGIOT:
//        strText = "IOT instruction, abort() on a PDP-11.";
//        break;
//    case SIGCLD:
//        strText = "Old System V name";
//        break;
    default:
        strText = "未知错误信号";
        break;
    }

    return strText;
}

//获取异常堆栈信息
void BackTraceHandler(int iSignalNo)
{
    QString strText = "";
    strText += QString("\n异常发送时间:%1\n").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss.zzz"));
    strText += QString("异常信号值:%1\n").arg(iSignalNo);
    strText += QString("异常信号原因:%1\n").arg(SignalText(iSignalNo));

    void* pBuf[ADDR_MAX_NUM] = {0};
    int iAddrNum = backtrace(pBuf, ADDR_MAX_NUM);
    strText += QString("堆栈地址数:%1\n").arg(iAddrNum);
    char** pSymbols = backtrace_symbols(pBuf, iAddrNum);
    if (0 == pSymbols)
    {
        strText += QString("无法获取堆栈信息\n");
        return;
    }
    int ii = 0;
    for (ii = 0; ii < iAddrNum; ii++)
    {
        strText += QString("%1 %2\n").arg(iAddrNum-ii).arg(pSymbols[ii]);
        //printf("%03d %s\n", iAddrNum-ii, pSymbols[ii]);
    }
    printf("\n");
    free(pSymbols);
    pSymbols = 0;
    WriteBackTrace(strText);
    exit(1); // QUIT PROCESS. IF NOT, MAYBE ENDLESS LOOP.
}

//记录异常堆栈信息到/userdata/bams/log/dump_***.txt
void WriteBackTrace(const QString& strText)
{
    QString strFile = QString("/userdata/bams/log/dump_%1.txt").arg(qApp->applicationName());

    QFile file(strFile);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append))
    {
        return;
    }
    file.write(strText.toUtf8());
    file.flush();
    file.close();
}

// void ErrorPoint()
// {
//     KG_LOG_INFO("ErrorPoint aaa");
//     CBattStack* pStack32 = m_pRTDB->getStack(31);
//     pStack32->usStackState = 0xBBBB;
//     KG_LOG_INFO("ErrorPoint bbb");
// }

// void InvalidArray()
// {
//     KG_LOG_INFO("InvalidArray aaa");

//     CBattStack* pStack0 = m_pRTDB->getStack(0);
//     pStack0->usStackTemp[99] = 1234;

//     KG_LOG_INFO("InvalidArray bbb");
// }

// int main(int argc, char *argv[])
// {
//     QApplication a(argc, argv);

//     InitBackTrace(); //先初始化异常处理

//     ErrorPoint(); //后触发异常
//     InvalidArray(); //后触发异常

//     return a.exec();
// }
